import math
import pymongo
import re
import copy
from WindPy import *
import Core.Gadget as Gadget
import Core.DataSeries as DataSeries
import Core.Global as Global

##################################################
#---Test---
def Test(value):
    v = Global.Get("Kek1",0)
    Global.Set("Key1", v + value)


def Build_Param_Str(params):
    #
    params_list = []
    for k, v in params.items():
        params_list.append(k + "=" + str(v))
    param_string = ";".join(params_list)
    #
    return param_string


# ---Wind Raw API---
# ---基础函数---
# ---fields is List; params is Dict---
def WSS(symbols, fields, params={}):

    if not isinstance(symbols, list):
        symbols = [symbols]

    if not isinstance(fields, list):
        fields = [fields]

    #---Build indictor string---
    countField = len(fields)
    fieldsStr = ""
    for i in range(countField):
        fieldsStr = fieldsStr + fields[i]
        if (i != countField - 1):
            fieldsStr = fieldsStr + ","

    #---Build Params String---
    paramsStr = ""
    for k, v in params.items():
        paramsStr = paramsStr + k + "=" + str(v) + ";"

    # ---Real Request---
    data = w.wss(symbols, fieldsStr, paramsStr)
    if data.ErrorCode != 0:
        print(data.Data)
        return None

    dataRecvCount = len(data.Data)
    Global.WIND_DATA_RECVED += dataRecvCount
    Global.WIND_DATA_RECVED_COUNT += 1
    # 每重复调用50次输出一次结果
    if Global.WIND_DATA_RECVED_COUNT % 50 == 0:
        print("Total Recv Data ", Global.WIND_DATA_RECVED, "@", datetime.now())

    #---Parse Fundamental Data---
    formattedData = []
    for iSymbol in range(len(symbols)):
        values = {}
        for iField in range(countField):
            value = data.Data[iField][iSymbol]
            #if value == None:
            #    value = 0
            values[fields[iField]] = value
        formattedData.append(values)

    #---Return values---
    return formattedData


# ---WSet 数据集---
# tablename = IndexConstituent | SectorConstituent
def WSET(tableName, params):
    #
    paramsList = []
    for k, v in params.items():
        paramsList.append(k + "=" + str(v))
    paramString = ";".join(paramsList)

    # Index Constituent
    data = w.wset(tableName, paramString)

    # ---
    if data.Data.__len__() == 0:
        print("WSET: No Data Fetched :" + paramString)
        return None

    #
    dataRecvCount = 0
    for d in data.Data:
        dataRecvCount += len(d)
    Global.WIND_DATA_RECVED += dataRecvCount
    Global.WIND_DATA_RECVED_COUNT += 1
    # 每重复调用50次输出一次结果
    if Global.WIND_DATA_RECVED_COUNT % 50 == 0:
        print("Total Recv Data ", Global.WIND_DATA_RECVED, "@", datetime.now())

    #---
    fields = data.Fields
    fieldsCount = len(fields)
    dataCount = len(data.Data[0])

    #---
    formattedData = []
    for i in range(dataCount):
        entry = {}
        for n in range(fieldsCount):
            entry[fields[n]] = data.Data[n][i]
        formattedData.append(entry)

    #---
    return formattedData


#---获取成分股及其权重---
def WSet_InstrumentList(datetime1, indexSymbol):
    # Index Constituent

    params = {}
    params["date"] =  Gadget.ToDateString2(datetime1)
    params["windcode"] = indexSymbol
    data = WSET("IndexConstituent", params)

    if data == None:
        return None, datetime1

    values = []
    #--- Field=date,wind_code,sec_name,i_weight ---
    for d in data:
        entry = {}
        entry["Symbol"] = d["wind_code"]
        if d["i_weight"] != None:
            entry["Weight"] = d["i_weight"] * 0.01
        else:
            entry["Weight"] = 0
        values.append(entry)

    #---Process datetime---
    dt = data[0]["date"]
    #---data.Data[0][0]---返回的时间日期有500毫秒的脏数据---
    dt = datetime(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second)

    return values, dt

# ---板块数据集---
# ---"全部A股"---a001010100000000
# ---"已摘牌股票" ---a001010m00000000
# ---"全部基金"---a201010700000000
# ---"全部基金(含未成立、已到期)"---1000008492000000
def WSet_Instruments(datetime1, sectorName):
    # Index Constituent
    params = {}
    params["date"] =  Gadget.ToDateString2(datetime1)
    #params["windcode"] = sectorName
    params["sectorid"] = sectorName
    #params["sectorid"] = sectorName
    data = WSET("sectorconstituent", params)

    if data == None:
        return [], datetime1

    if "OUTMESSAGE" in data[0]:
        print(data)
        return [], datetime1

    values = []
    #--- Field=date,wind_code,sec_name,i_weight ---
    for d in data:
        entry = {}
        entry["Symbol"] = d["wind_code"]
        entry["Name"] = d["sec_name"]
        values.append(entry)

    #---Process datetime---
    dt = data[0]["date"]
    #---data.Data[0][0]---返回的时间日期有500毫秒的脏数据---
    dt = datetime(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second)

    return values, dt


def WSD_DailyQuote(symbol, instrument_type, datetime1, datetime2, logger=None):
    #
    instrumentType = instrument_type
    # name = symbol + "_Time_86400_Bar"
    # dataObjects = DataSeries.DataSeries(name)  # List Modified to DataSeries Object 2018-3-28
    dataObjects = []
    # ---Params---
    param = ""

    # ---Fields---
    fields = "open,high,low,close,volume,amt";
    # fields = "open,high,low,close,adjfactor,volume,amt,oi,dealnum,turn,free_turn,trade_status,total_shares,free_float_shares"; // sec_name, industry_sw
    if instrumentType == "Future":
        fields = fields + ",oi"

    elif instrumentType == "Stock":
        fields = fields + ",adjfactor,dealnum,turn,free_turn,trade_status,total_shares,free_float_shares"

    elif instrumentType == "Index":
        fields = fields + ",turn, free_turn, total_shares, free_float_shares"

    elif instrumentType == "MutualFund":
        fields = "nav,NAV_adj,NAV_acc,NAV_date"  # 单位净值; 复权单位净值; 累计单位净值

    elif instrumentType == "Option":
        fields = fields + ",oi,settle,ptmtradeday,ptmday,us_impliedvol"

    elif instrumentType == "Bond":
        # 基于中债的：净价 全价 应计利息 TYM(收益率) 修正久期 剩余年限
        fields = fields + ",net_cnbd, dirty_cnbd, accruedinterest_cnbd, yield_cnbd, modidura_cnbd, matu_cnbd"
        param = "credibility=1"

    # ---Request Functions---
    data = w.wsd(symbol, fields, datetime1, datetime2, param);

    # ---Check---
    if data.ErrorCode != 0:
        if logger:
            logger.info("Error " + symbol)
            logger.info(data.Data)
        print("Error " + symbol)
        print(data.Data)
        # PlaySound()
        return None

    dataRecvCount = 0
    for d in data.Data:
        dataRecvCount += len(d)
    Global.WIND_DATA_RECVED += dataRecvCount
    print("Total Recv Data ", Global.WIND_DATA_RECVED)

    fields = data.Fields
    count = len(data.Times)
    for i in range(count):
        # 虽然返回了数据，但是数据为空
        if data.Data[0][i] == None:
            continue

        #
        dataObject = {}
        # dataObject["DataSeries"] = name
        dataObject["Symbol"] = symbol
        # dataObject["Size"] = 86400
        # dataObject["Bar_Type"] = "Time"
        # dataObject["Values"] = {}

        # ---Process Dirty DateTime---
        datetime0 = data.Times[i]

        # ---Process Open DateTime---
        if instrumentType in ["Stock", "Index", "Option"]:
            dataObject["Open_DateTime"] = datetime0.strftime('%Y-%m-%d 09:30:00.000')
        elif instrumentType == "Future":
            dataObject["Open_DateTime"] = datetime0.strftime('%Y-%m-%d 09:00:00.000')

        # ---Process Closed Time---
        closingTime = time(15, 0, 0)
        datetime0 = datetime.combine(datetime0, closingTime)
        # dataObject["DateTime"] = datetime0.strftime('%Y-%m-%d 15:00:00.000')
        dataObject["DateTime"] = datetime0
        dataObject["Date"] = Gadget.ToDate(datetime0)
        sDateTime = dataObject["DateTime"].strftime('%Y-%m-%d 15:00:00.000')

        # build key
        # dataObject["UTC_DateTime"] = Gadget.ToUTCDateTime(datetime0)
        # dataObject["Key"] = symbol + "_Time_86400_Bar" + "_" + sDateTime
        dataObject["Key"] = symbol + "_" + dataObject["Date"].strftime('%Y-%m-%d')


        #
        for iField in range(len(data.Fields)):
            field = data.Fields[iField]

            # ---Common Fields---
            if field == "OPEN":
                dataObject["Open"] = data.Data[iField][i]
            elif field == "HIGH":
                dataObject["High"] = data.Data[iField][i]
            elif field == "LOW":
                dataObject["Low"] = data.Data[iField][i]
            elif field == "CLOSE":
                dataObject["Close"] = data.Data[iField][i]
            elif field == "VOLUME":
                dataObject["Volume"] = data.Data[iField][i]
            elif field == "AMT":
                dataObject["Money"] = data.Data[iField][i]
            elif field == "TRADE_STATUS":
                dataObject["Trade_Status"] = data.Data[iField][i]

            # ---Stock---
            elif field == "ADJFACTOR":
                dataObject["AdjFactor"] = data.Data[iField][i]
            elif field == "DEALNUM":
                dataObject["Deal_Number"] = data.Data[iField][i]
            elif field == "TURN":
                dataObject["Turn"] = data.Data[iField][i]
            elif field == "FREE_TURN":
                dataObject["Free_Turn"] = data.Data[iField][i]
            elif field == "TOTAL_SHARES":
                dataObject["Total_Shares"] = data.Data[iField][i]
            elif field == "FREE_FLOAT_SHARES":
                dataObject["Free_Float_Shares"] = data.Data[iField][i]

            # ---Future---
            elif field == "OI":
                dataObject["Open_Int"] = data.Data[iField][i]

            # ---Fund---
            elif field == "NAV":
                dataObject["Net_Asset_Value"] = data.Data[iField][i]
            elif field == "NAV_ADJ":
                dataObject["Adjusted_Net_Asset_Value"] = data.Data[iField][i]
            elif field == "NAV_ACC":
                dataObject["Accumulated_Net_Asset_Value"] = data.Data[iField][i]
            elif field == "NAV_DATE":
                dataObject["NAV_date"] = data.Data[iField][i]

            # ---Option---
            elif field == "settle".upper():
                dataObject["Settlement"] = data.Data[iField][i]
            elif field == "ptmtradeday".upper():
                dataObject["Trading_Days_Left"] = data.Data[iField][i]
            elif field == "ptmday".upper():
                dataObject["Calender_Days_Left"] = data.Data[iField][i]
            elif field == "us_impliedvol".upper():
                dataObject["Wind_Implied_Volatility"] = data.Data[iField][i]

            # ---Bond---
            elif field == "net_cnbd".upper():
                dataObject["NetPriceCNBD"] = data.Data[iField][i]
            elif field == "dirty_cnbd".upper():
                dataObject["DirtyPriceCNBD"] = data.Data[iField][i]
            elif field == "accruedinterest_cnbd".upper():
                dataObject["AccruedInterestCNBD"] = data.Data[iField][i]
            elif field == "yield_cnbd".upper():
                dataObject["YTMCNBD"] = data.Data[iField][i]
            elif field == "modidura_cnbd".upper():
                dataObject["ModifiedDurationCNBD"] = data.Data[iField][i]
            elif field == "matu_cnbd".upper():
                dataObject["TermLeftCNBD"] = data.Data[iField][i]

        # ---Invalid Data---
        if "Close" in dataObject and (dataObject["Close"] == None or math.isnan(dataObject["Close"])):
            continue

        # ---For Stock Adjusted---
        if instrumentType == "Stock":
            dataObject["BOpen"] = dataObject["Open"] * dataObject["AdjFactor"]
            dataObject["BHigh"] = dataObject["High"] * dataObject["AdjFactor"]
            dataObject["BLow"] = dataObject["Low"] * dataObject["AdjFactor"]
            dataObject["BClose"] = dataObject["Close"] * dataObject["AdjFactor"]

        if instrumentType == "MutualFund":
            if dataObject["NAV_date"].date() < dataObject["DateTime"].date():
                continue
            del dataObject["NAV_date"]
            del dataObject["DateTime"]

        #
        for k, v in dataObject.items():
            if not isinstance(v, float):
                continue
            if math.isnan(v):
                dataObject[k] = None
        #
        dataObjects.append(dataObject)

    return dataObjects




